/*
 * Copyright (c) 2006,2009 Charles S. Wilson
 * 
 * Permission is hereby granted, free of charge, to any person obtaining a 
 * copy of this software and associated documentation files (the "Software"), 
 * to deal in the Software without restriction, including without limitation 
 * the rights to use, copy, modify, merge, publish, distribute, sublicense, 
 * and/or sell copies of the Software, and to permit persons to whom the 
 * Software is furnished to do so, subject to the following conditions:
 * 
 * The above copyright notice and this permission notice shall be included 
 * in all copies or substantial portions of the Software.
 * 
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 
 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 
 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR 
 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 
 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 
 * OTHER DEALINGS IN THE SOFTWARE.
 */
#ifndef RUN2_UTIL_H
#define RUN2_UTIL_H

#include <stdarg.h>
#include <ustr.h>

#define PATH_SEP_CHAR_STR "/"
#define SEP_CHAR ":"
#define SEP_CHARS ":"

#define RUN2_LOG_ALWAYS -1 /* used for --help, etc, even when --silent */
#define RUN2_LOG_FATAL   0 /* normal --silent behavior */
#define RUN2_LOG_ERROR   3 /* normal --no-silent behavior */
#define RUN2_LOG_WARN    4
#define RUN2_LOG_INFO    6 /* normal --verbose behavior */
#define RUN2_LOG_DEBUG   7 /* normal --debug[=1] behavior */

#define RUN2_DEFAULT_LOG_SILENT_LEVEL   RUN2_LOG_FATAL
#define RUN2_DEFAULT_LOG_LEVEL          RUN2_LOG_ERROR
#define RUN2_DEFAULT_LOG_VERBOSE_LEVEL  RUN2_LOG_INFO

#if defined(PATH_MAX)
# define RUN2_PATHMAX PATH_MAX
#elif defined(MAXPATHLEN)
# define RUN2_PATHMAX MAXPATHLEN
#else
# define RUN2_PATHMAX 1024
#endif

#if __STDC_VERSION__ < 199901L
# if __GNUC__ >= 2
#  define __func__ __FUNCTION__
# else
#  define __func__ "<unknown>"
# endif
#endif

#define USTR_CHECK(a)  ustr_check (a, __FILE__, __LINE__)
Ustr* ustr_check (Ustr *s, const char *fn, int ln);

char* run2_pfopen     (char *retval, const char *name, const char *dirs);
int   run2_fileExists (char* fullname, const char* path, const char* name);
void  run2_message_   (int level, const char* fmt, ...);
void  run2_vmessage_  (int level, const char* fmt, va_list args);
int   run2_countargv  (char **vector);
void  run2_freeargv   (char **vector);

const char *run2_get_program_name (void);
void run2_set_program_name (const char *p);
const char *run2_basename (const char *p);

void run2_malloc_exit (void);
void run2_error (int status, int errnum, const char *message, ...);
void *run2_malloc  (size_t);
void *run2_realloc (void *, size_t);
char *run2_strdup  (const char *arg);
char *run2_extend_str (const char *orig_value, const char *add, int to_end);
int run2_strtol(char *arg, long* value);
char *run2_get_homedir (const char *user);

/* modes */
int run2_gui_is_allowed(void);
int run2_tty_is_allowed(void);
int run2_get_verbose_level(void);
void run2_set_gui_mode(int mode); /* bool: true=enabled */
void run2_set_tty_mode(int mode); /* bool: true=enabled */
void run2_set_verbose_level(int level);  /* int: higher turns on more messages */


#define realMsg(fmt, ...)    run2_message_(RUN2_LOG_ALWAYS, fmt, ## __VA_ARGS__)
#define vrealMsg(fmt, args)  run2_vmessage_(RUN2_LOG_ALWAYS, fmt, args)

#ifndef DEBUG
#define fatalMsg(fmt, ...) \
   do { if (RUN2_LOG_FATAL <= run2_get_verbose_level()) { \
        run2_message_(RUN2_LOG_FATAL, fmt, ## __VA_ARGS__); } \
   } while(0)
#define errorMsg(fmt, ...) \
   do { if (RUN2_LOG_ERROR <= run2_get_verbose_level()) { \
        run2_message_(RUN2_LOG_ERROR, fmt, ## __VA_ARGS__); } \
   } while(0)
#define warnMsg(fmt, ...) \
   do { if (RUN2_LOG_WARN <= run2_get_verbose_level()) { \
        run2_message_(RUN2_LOG_WARN, fmt, ## __VA_ARGS__); } \
   } while(0)
#define infoMsg(fmt, ...) \
   do { if (RUN2_LOG_INFO <= run2_get_verbose_level()) { \
        run2_message_(RUN2_LOG_INFO, fmt, ## __VA_ARGS__); } \
   } while(0)
#define debugMsg(level, fmt, ...) \
  do { if (level + RUN2_LOG_INFO <= run2_get_verbose_level()) { \
       run2_message_(level + RUN2_LOG_INFO, fmt, ## __VA_ARGS__); } \
  } while(0)

#define vfatalMsg(fmt, ...) \
   do { if (RUN2_LOG_FATAL <= run2_get_verbose_level()) { \
        run2_vmessage_(RUN2_LOG_FATAL, fmt, ## __VA_ARGS__); } \
   } while(0)
#define verrorMsg(fmt, ...) \
   do { if (RUN2_LOG_ERROR <= run2_get_verbose_level()) { \
        run2_vmessage_(RUN2_LOG_ERROR, fmt, ## __VA_ARGS__); } \
   } while(0)
#define vwarnMsg(fmt, ...) \
   do { if (RUN2_LOG_WARN <= run2_get_verbose_level()) { \
        run2_vmessage_(RUN2_LOG_WARN, fmt, ## __VA_ARGS__); } \
   } while(0)
#define vinfoMsg(fmt, ...) \
   do { if (RUN2_LOG_INFO <= run2_get_verbose_level()) { \
        run2_vmessage_(RUN2_LOG_INFO, fmt, ## __VA_ARGS__); } \
   } while(0)
#define vdebugMsg(level, fmt, ...) \
   do { if (level + RUN2_LOG_INFO <= run2_get_verbose_level()) { \
        run2_vmessage_(level + RUN2_LOG_INFO, fmt, ## __VA_ARGS__); } \
  } while(0)

#else
/* if DEBUG, then all messages are printed */
#define fatalMsg(fmt, ...)          run2_message_ (RUN2_LOG_FATAL, fmt, ## __VA_ARGS__);
#define errorMsg(fmt, ...)          run2_message_ (RUN2_LOG_ERROR, fmt, ## __VA_ARGS__);
#define warnMsg(fmt, ...)           run2_message_ (RUN2_LOG_WARN,  fmt, ## __VA_ARGS__);
#define infoMsg(fmt, ...)           run2_message_ (RUN2_LOG_INFO,  fmt, ## __VA_ARGS__);
#define debugMsg(level, fmt, ...)   run2_message_ (level + RUN2_LOG_INFO, fmt, ## __VA_ARGS__)
#define vfatalMsg(fmt, args)        run2_vmessage_(RUN2_LOG_FATAL, fmt, args);
#define verrorMsg(fmt, args)        run2_vmessage_(RUN2_LOG_ERROR, fmt, args);
#define vwarnMsg(fmt, args)         run2_vmessage_(RUN2_LOG_WARN,  fmt, args);
#define vinfoMsg(fmt, args)         run2_vmessage_(RUN2_LOG_INFO,  fmt, args);
#define vdebugMsg(level, fmt, args) run2_vmessage_(level + RUN2_LOG_INFO, fmt, args)
#endif

#endif

